package com.klxedu.ms.gateway;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.security.Principal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import io.prometheus.client.hotspot.DefaultExports;
import io.prometheus.client.spring.boot.EnablePrometheusEndpoint;
import io.prometheus.client.spring.boot.EnableSpringBootMetricsCollector;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.klxedu.ms.gateway.core.json.BaseJsonObject;
import com.klxedu.ms.gateway.core.json.JsonErrorObject;
import com.klxedu.ms.gateway.core.json.JsonMapObject;
import com.klxedu.ms.gateway.core.json.JsonObject;
import com.klxedu.ms.gateway.core.json.JsonSuccessObject;
import com.klxedu.ms.gateway.core.json.ResponesCode;
import com.klxedu.ms.gateway.security.authentication.CustomUserDatails;
import com.klxedu.ms.gateway.security.authentication.IAuthenticatedUser;
import com.klxedu.ms.gateway.security.authentication.impl.AuthenticatedUserImpl;
import com.klxedu.ms.gateway.security.client.UserFeignClient;
import com.klxedu.ms.gateway.security.client.service.LoginUser;
import com.klxedu.ms.gateway.utils.VerifyCodeUtils;
import com.klxedu.ms.gateway.zullfilter.AccessUserNameFilter;
import com.klxedu.ms.gateway.zullfilter.RepeatSubmitFilter;

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
@EnableFeignClients
@Controller
@EnablePrometheusEndpoint
@EnableSpringBootMetricsCollector
public class UiApplication implements CommandLineRunner {

	@Autowired
	private AuthServerProperties authServerProperties;

	@Autowired
	private UserFeignClient userFeignClient;

	@GetMapping("/user")
	@ResponseBody
	public Map<String, Object> user(Principal user, HttpServletRequest request) {
		Map<String, Object> result = new HashMap<>();
		if (user instanceof Authentication) {
			Authentication authentication = (Authentication) user;
			CustomUserDatails principal = (CustomUserDatails) authentication.getPrincipal();
			IAuthenticatedUser extendAccountInfo = (IAuthenticatedUser) principal.getExtendAccountInfo();
			// 保存用户信息,字符串类型
			if (StringUtils.isEmpty(extendAccountInfo)) {
				extendAccountInfo = new AuthenticatedUserImpl("testID", "testLogin", "testName", "testPassword");
			}
			request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_LOGINID, extendAccountInfo.getLoginID());
			request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_USERID, extendAccountInfo.getEntityID());
			request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_USERNAME, extendAccountInfo.getName());
			request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_DEPARTID,
					extendAccountInfo.getDepartID());
			request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_SCOPECODE,
					extendAccountInfo.getScopeCodes() != null && extendAccountInfo.getScopeCodes().length > 0
							? extendAccountInfo.getScopeCodes()[0]
							: "");
			request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_UNITSCOPECODE,
					extendAccountInfo.getUnitScopeCodes() != null && extendAccountInfo.getUnitScopeCodes().length > 0
							? extendAccountInfo.getUnitScopeCodes()[0]
							: "");
			request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_ROLES, principal.getAuthorities().stream()
					.map(GrantedAuthority::getAuthority).collect(Collectors.joining(",")));
			result.put("authenticated", authentication.isAuthenticated());
		}
		return result;
	}

	@GetMapping("/user/listScope")
	@ResponseBody
	public JsonMapObject getUserScopeList(HttpServletRequest request) {
		JsonMapObject result = new JsonMapObject();
		String loginID = (String) request.getSession().getAttribute(AuthServerConstants.SESSION_KEY_LOGINID);
		BaseJsonObject<LoginUser> userResult = userFeignClient.getLoginUserByUserName(loginID);
		LoginUser loginUser = userResult.getData();
		if (loginUser.getSysIdentityCodes().contains(LoginUser.SYS_IDENTITY_ADMIN)) {
			String currentScope = (String) request.getSession().getAttribute(AuthServerConstants.SESSION_KEY_SCOPECODE);
			result.put("result", loginUser.getScopeMapList());
			result.put("current", currentScope);
		} else {
			result.setCode(ResponesCode.ERROR);
			result.setMessage("当前用户无管理范围权限");
		}
		return result;
	}

	@GetMapping("/user/setScope")
	@ResponseBody
	public JsonObject<Object> setCurrentScope(HttpServletRequest request,
			@RequestParam(name = "scopeCode", required = true) String scopeCode) {
		String loginID = (String) request.getSession().getAttribute(AuthServerConstants.SESSION_KEY_LOGINID);
		BaseJsonObject<LoginUser> userResult = userFeignClient.getLoginUserByUserName(loginID);
		boolean isContains = false;
		String unitScopeCode = "";
		for (Map<String, String> map : userResult.getData().getScopeMapList()) {
			if (map.get(AuthServerConstants.SCOPE_CODE_KEY).equals(scopeCode)) {
				isContains = true;
				unitScopeCode = map.get(AuthServerConstants.UNIT_SCOPE_CODE_KEY);
			}
		}
		if (isContains) {
			request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_SCOPECODE, scopeCode);
			request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_UNITSCOPECODE, unitScopeCode);
			return new JsonSuccessObject<>();
		}
		return new JsonErrorObject<>("当前用户无" + scopeCode + "范围权限");
	}
	@RequestMapping("/open/mem")
	@ResponseBody
	public String home(HttpServletRequest request) {
		MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();

		MemoryUsage memoryUsage = memoryMXBean.getHeapMemoryUsage(); // 椎内存使用情况

		long totalMemorySize = memoryUsage.getInit(); // 初始的总内存

		long maxMemorySize = memoryUsage.getMax(); // 最大可用内存

		long usedMemorySize = memoryUsage.getUsed(); // 已使用的内存
		return "totalMemory:" + totalMemorySize / (1024 * 1024) + "M freeMemory:"
				+ (totalMemorySize - usedMemorySize) / (1024 * 1024) + "M maxMemory:" + maxMemorySize / (1024 * 1024)
				+ "M usedMemory:"+usedMemorySize/(1024*1024)+"M";
	}
	/**
	 * 测试方法
	 * 
	 * @param user
	 * @return
	 */
	@GetMapping("/user_admin")
	@ResponseBody
	public Principal user(Principal user) {
		return user;
	}

	@GetMapping("/user/generateCaptchaImage")
	public void generateCaptchaNumImage(HttpServletRequest request, HttpServletResponse response, Model model)
			throws IOException {
		String captcha = VerifyCodeUtils.generateVerifyCode(authServerProperties.getCaptchaSize());
		request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_CAPTCHA, captcha);
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_CAPTCHA_TIME, dateFormat.format(new Date()));
		response.setContentType("image/jpeg");
		VerifyCodeUtils.outputImage(120, 40, response.getOutputStream(), captcha);
	}

	@GetMapping("/user/generateCaptchaNum")
	@ResponseBody
	public String generateCaptchaNum(HttpServletRequest request, HttpServletResponse response, Model model) {
		String captcha = VerifyCodeUtils.generateVerifyCode(authServerProperties.getCaptchaSize());
		request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_CAPTCHA, captcha);
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		request.getSession().setAttribute(AuthServerConstants.SESSION_KEY_CAPTCHA_TIME, dateFormat.format(new Date()));
		return captcha;
	}

	@GetMapping("/user/validateCaptcha")
    @ResponseBody
    public JsonObject<Object> validateCaptchaImage(HttpServletRequest request, HttpServletResponse response, Model model) {
        // 返回验证码
        String requestCaptcha = request.getParameter(AuthServerConstants.REQUEST_KEY_CAPTCHA);
        // session中获取验证码
        String sessionCaptcha = (String) request.getSession().getAttribute(AuthServerConstants.SESSION_KEY_CAPTCHA);
        String generateTime = (String) request.getSession()
                .getAttribute(AuthServerConstants.SESSION_KEY_CAPTCHA_TIME);
        if (!StringUtils.isEmpty(generateTime)) {
            // 校验时间是否在有效期内
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date generateDate = null;
            try {
                generateDate = dateFormat.parse(generateTime);
                Date date = new Date();
                String nowDate = dateFormat.format(date);
                long time = (dateFormat.parse(nowDate)).getTime() - generateDate.getTime();
                if ((time / 1000) > authServerProperties.getCaptchaTimeout()) {// 校验时间为5秒
                    return new JsonErrorObject<>("验证码已超时。");
                }
            } catch (ParseException e) {
                return new JsonErrorObject<>("验证码校验失败。");
            }
        }
		if (StringUtils.isEmpty(requestCaptcha) || StringUtils.isEmpty(sessionCaptcha)
				|| !requestCaptcha.toUpperCase().equals(sessionCaptcha.toUpperCase())) {
			return new JsonErrorObject<>("验证码校验失败。");
		}
        // 校验后清空session中的验证码
        request.getSession().removeAttribute(AuthServerConstants.SESSION_KEY_CAPTCHA);
        request.getSession().removeAttribute(AuthServerConstants.SESSION_KEY_CAPTCHA_TIME);
        return new JsonSuccessObject<>("验证码校验成功。");
	}

	@GetMapping(value = "/{path:[^\\.]*}")
	public String redirect() {
		return "forward:/";
	}

	@Bean
	public AccessUserNameFilter accessUserNameFilter() {
		return new AccessUserNameFilter();
	}

	@Bean
	public RepeatSubmitFilter repeatSubmitFilter() {
		return new RepeatSubmitFilter();
	}

	public static void main(String[] args) {
		SpringApplication.run(UiApplication.class, args);
	}

	@Bean
	@RefreshScope
	@ConfigurationProperties("zuul")
	public ZuulProperties zuulProperties() {
		return new ZuulProperties();
	}

	@Override
	public void run(String... args) throws Exception {
		DefaultExports.initialize();
	}
}
